<?php

namespace app\services;

use app\traits\Page;
use plugin\admin\app\model\Goods;
use plugin\admin\app\model\PrizeDrawActivity;
use plugin\admin\app\model\PrizeDrawActivityGood;
use plugin\admin\app\model\PrizeDrawGood;
use plugin\admin\app\model\User;
use plugin\admin\app\model\UserPrizeDraw;
use plugin\admin\app\model\UserProfile;
use support\Db;
use Webman\Event\Event;

class PrizeDrawService
{
    public static function getOpenMessage()
    {
        $activities = PrizeDrawActivity::where('status', PrizeDrawActivity::STATUS_OPEN)->orderByDesc('id')->get()->toArray();

        $messages = [];
        foreach ($activities as &$activity) {
            self::processData($activity);
            $messages[] = [
                'id' => $activity['id'],
                'name' => $activity['name'] . '已开奖',
            ];
        }

        return $messages;
    }

    public static function list($page = 1, $length = 10, $type = PrizeDrawActivity::TYPE_SINGLE)
    {
        $offset = ($page - 1) * $length;

        $query = PrizeDrawActivity::select(['id', 'pid', 'status', 'need_buy_count', 'target_count', 'fake_sale_count', 'sale_count', 'fake_process', 'start_time', 'end_time', 'desc', 'loop_count', 'name'])->where('status', PrizeDrawActivity::STATUS_ACTIVE)->where('start_time', '<=', time())->where('type', $type);

        $totalCount = (clone $query)->count();
        $list = (clone $query)->offset($offset)->limit($length)->get()->toArray();

        $activityIds = array_column($list, 'id');

        $prizeDrawActivityGoodList = PrizeDrawActivityGood::whereIn('prize_draw_activity_id', $activityIds)->get()->toArray();

        $goodsIds = array_column($prizeDrawActivityGoodList, 'goods_id');
        $goodsList = Goods::select(['id', 'thumb', 'name', 'price', 'desc'])->whereIn('id', $goodsIds)->get()->toArray();
        $goodsList = array_combine(
            array_column($goodsList, 'id'),
            array_values($goodsList)
        );

        foreach ($list as &$item) {

            foreach ($prizeDrawActivityGoodList as $prizeDrawActivityGood) {
                if ($item['id'] == $prizeDrawActivityGood['prize_draw_activity_id']) {
                    $goods = $goodsList[$prizeDrawActivityGood['goods_id']] ?? [];
                    $goods['thumb'] = full_url($goods['thumb']);
                    $item['goods_list'][] = $goods;
                }
            }

            self::processData($item);
        }

        return Page::wrap($totalCount, $page, $length, $list);
    }

    public static function detail($aid)
    {
        $activity = PrizeDrawActivity::select(['id', 'pid', 'status', 'need_buy_count', 'target_count', 'fake_sale_count', 'sale_count', 'fake_process', 'start_time', 'end_time', 'desc', 'loop_count', 'name'])->where('id', $aid)->first();

        self::processData($activity);

        $prizeDrawActivityGoodList = PrizeDrawActivityGood::where('prize_draw_activity_id', $activity['id'])->get()->toArray();

        $goodsIds = array_column($prizeDrawActivityGoodList, 'goods_id');
        $goodsList = Goods::select(['id', 'thumb', 'name', 'price', 'desc', 'market_price', 'sale_count'])->whereIn('id', $goodsIds)->get()->toArray();

        foreach ($goodsList as $key=>$goods) {
            $goods['thumb'] = full_url($goods['thumb']);
            $goodsList[$key] = $goods;
        }

        $activity['need_buy_goods'] = $goodsList;
        $activity['goods'] = self::goodsList($activity['id']);
        $activity['history_goods_list'] = self::historyList($activity['id']);
        $activity['history_win_user_list'] = self::historyWinList($activity['id']);
        if (get_user_id()) {
            $activity['has_count'] = UserPrizeDraw::where('user_id', get_user_id())->where('aid', $aid)->count();
        } else {
            $activity['has_count'] = 0;
        }



        return $activity;
    }

    public static function winUserList($aid)
    {
        $winUserList = UserPrizeDraw::select(['id', 'user_id', 'number', 'level'])->where('aid', $aid)->where('status', UserPrizeDraw::STATUS_WIN)->orderBy('id', 'desc')->get()->toArray();

        $uids = array_column($winUserList, 'user_id');
        $userProfiles = UserProfile::select(['user_id', 'nickname', 'avatar'])->whereIn('user_id', $uids)->get()->keyBy('user_id')->toArray();

        $users = User::select(['id', 'mobile'])->whereIn('id', $uids)->get()->keyBy('id')->toArray();

        foreach ($winUserList as &$item) {
            $item['nickname'] = $userProfiles[$item['user_id']]['nickname'] ?? '';
            $item['avatar'] = $userProfiles[$item['user_id']]['avatar'] ?? '';
            $item['mobile'] = format_mobile($users[$item['user_id']]['mobile']) ?? '';
            $item['level_text'] = PrizeDrawGood::getLevelText($item['level']);
        }

        return $winUserList;
    }

    public static function historyWinList($aid)
    {
        $activity = PrizeDrawActivity::where('id', $aid)->first();
        $activities = PrizeDrawActivity::select(['id', 'loop_count', 'open_time'])->where('group_id', $activity['group_id'])->where('id', '<>', $aid)->orderByDesc('loop_count')->get()->toArray();

        foreach ($activities as $key=>$activity) {
            $activities[$key]['users'] = self::winUserList($activity['id']);
        }

        return $activities;
    }

    public static function goodsList($aid)
    {
        $prizeDrawGoodsList = PrizeDrawGood::where('aid', $aid)->get()->toArray();
        $pids = array_column($prizeDrawGoodsList, 'pid');

        $goodsList = Goods::select(['id', 'name', 'thumb', 'price'])->whereIn('id', $pids)->get()->toArray();

        foreach ($goodsList as $key=>$goods) {
            $goods['thumb'] = full_url($goods['thumb']);

            foreach ($prizeDrawGoodsList as $v) {
                if ($v['pid'] == $goods['id']) {
                    $goods['count'] = $v['count'];
                    $goods['level'] = $v['level'];
                    $goods['level_text'] = PrizeDrawGood::getLevelText($v['level']);
                    $goods['offline'] = $v['offline'];
                }
            }

            $goodsList[$key] = $goods;
        }

        return array_values($goodsList);
    }

    public static function historyList($aid)
    {
        $activity = PrizeDrawActivity::where('id', $aid)->first();
        $activities = PrizeDrawActivity::select(['id', 'loop_count', 'open_time'])->where('group_id', $activity['group_id'])->where('status', PrizeDrawActivity::STATUS_OPEN)->orderByDesc('loop_count')->get()->toArray();

        foreach ($activities as $key=>$activity) {
            $activities[$key]['goods'] = self::goodsList($activity['id']);
        }

        return $activities;
    }

    public static function new($activity)
    {
        $goodsList = PrizeDrawGood::select(['pid', 'level', 'count'])->where('aid', $activity['id'])->get()->toArray();
        $prizeDrawActivityGoodsList = PrizeDrawActivityGood::select(['prize_draw_activity_id', 'goods_id'])->where('prize_draw_activity_id', $activity['id'])->get()->toArray();

        unset($activity['id']);
        $activity['status'] = PrizeDrawActivity::STATUS_ACTIVE;
        $activity['end_time'] = time() + $activity['end_time'] - $activity['start_time'];
        $activity['start_time'] = time();
        $activity['sale_count'] = 0;
        $activity['loop_count'] += 1;

        $activityId = PrizeDrawActivity::insertGetId($activity->toArray());

        foreach ($goodsList as $k=>$v) {
            $v['aid'] = $activityId;
            $goodsList[$k] = $v;
        }

        foreach ($prizeDrawActivityGoodsList as $k=>$v) {
            $v['prize_draw_activity_id'] = $activityId;
            $prizeDrawActivityGoodsList[$k] = $v;
        }

        PrizeDrawGood::insert($goodsList);
        PrizeDrawActivityGood::insert($prizeDrawActivityGoodsList);

    }

    public static function autoOpen()
    {
        Db::beginTransaction();

        try {
            $activityList = PrizeDrawActivity::where('status', PrizeDrawActivity::STATUS_ACTIVE)->get()->toArray();

            foreach ($activityList as $activity) {
                self::open($activity['id']);
            }

            Db::commit();
        } catch (\Exception $e) {
            Db::rollBack();
        }

    }

    public static function open($aid, $ignoreCheckTime = false, $autoNew = true)
    {
        //抽奖活动
        $activity = PrizeDrawActivity::where('id', $aid)->first();

        if ($activity['status'] != PrizeDrawActivity::STATUS_ACTIVE) {
            return;
        }

        //如果不忽略时间检查
        if (!$ignoreCheckTime) {

            //未到期略过
            if ($activity['end_time'] > time()) {
                return;
            }

            //如果未开启“未到达目标自动开奖"，则不开奖
            if (!$activity['unfinish_prize_draw'] && $activity['sale_count'] < $activity['target_count'])  {
                $activity->status = PrizeDrawActivity::STATUS_CLOSE;
                $activity->save();

                if ($autoNew && $activity['auto_loop']) {
                    PrizeDrawService::new($activity);
                }

                return;
            }

        }

        //获取抽奖号码
        $list = UserPrizeDraw::where('aid', $aid)->get()->toArray();
        $numbers = array_column($list, 'number');

        $activityGoodsList = PrizeDrawGood::where('aid', $aid)->where('offline', 0)->orderByDesc('level')->get()->toArray();
        $pids = array_column($activityGoodsList, 'pid');
        $goodsList = Goods::whereIn('id', $pids)->get()->keyBy('id')->toArray();

        //开奖
        foreach ($activityGoodsList as $goods) {
            $length = count($numbers);
            $count = min($goods['count'], $length);

            //冗余奖品信息
            $prizeDrawGoodsInfo = $goodsList[$goods['pid']];
            PrizeDrawGood::where('id', $goods['id'])->update([
                'goods_info' => json_encode($prizeDrawGoodsInfo, JSON_UNESCAPED_UNICODE)
            ]);

            if ($count <= 0) {
                break;
            }

            $keys = array_rand($numbers, $count);

            if (!is_array($keys)) {
                $keys = array($keys);
            }

            foreach ($keys as $key) {
                UserPrizeDraw::where('aid', $aid)->where('number', $numbers[$key])->update([
                    'level' => $goods['level'],
                    'status' => UserPrizeDraw::STATUS_WIN
                ]);

                unset($numbers[$key]);
            }
        }

        //未中奖用户
        UserPrizeDraw::where('aid', $aid)->where('status', UserPrizeDraw::STATUS_WAIT)->update([
            'status' => UserPrizeDraw::STATUS_LOSE
        ]);

        //修改抽奖活动状态
        $activity->status = PrizeDrawActivity::STATUS_OPEN;
        $activity->open_time = date('Y-m-d H:i:s');
        $activity->save();

        //冗余抽奖商品信息
        $prizeDrawGoodsObjects = PrizeDrawActivityGood::where('prize_draw_activity_id', $aid)->get()->toArray();
        $prizeDrawGoodsIds = array_column($prizeDrawGoodsObjects, 'goods_id');

        $prizeDrawGoodsList = Goods::whereIn('id', $prizeDrawGoodsIds)->get()->keyBy('id')->toArray();

        foreach ($prizeDrawGoodsObjects as $prizeDrawGoods) {
            $prizeDrawGoods['goods_info'] = json_encode($prizeDrawGoodsList[$prizeDrawGoods['goods_id']], JSON_UNESCAPED_UNICODE);
            PrizeDrawActivityGood::where('id', $prizeDrawGoods['id'])->update($prizeDrawGoods);
        }

        //如果开启了自动循环
        if ($autoNew && $activity['auto_loop']) {
            PrizeDrawService::new($activity);
        }

        Event::dispatch('after-prize-draw', $activity);
    }

    public static function goodsActivity($pid)
    {
        $activity = self::goodsActivityOriginal($pid);

        if ($activity) {
            self::processData($activity);
        }

        return $activity;
    }

    public static function goodsActivityOriginal($pid) {
        $goodsList = PrizeDrawActivityGood::where('goods_id', $pid)->get()->toArray();
        $activityIds = array_column($goodsList, 'prize_draw_activity_id');

        return PrizeDrawActivity::select(['id', 'pid', 'status', 'need_buy_count', 'target_count', 'fake_sale_count', 'sale_count', 'fake_process', 'start_time', 'end_time', 'desc', 'loop_count', 'name'])->whereIn('id', $activityIds)->where('status', PrizeDrawActivity::STATUS_ACTIVE)->where('start_time', '<=', time())->first();
    }

    public static function processData(&$item)
    {
        $process = bcdiv($item['sale_count'], $item['target_count'], 2) * 100;
        $process = min($process, 100);
        $item['process'] = max($process, $item['fake_process']);
        $item['sale_count'] = max($item['sale_count'], $item['fake_sale_count']);
        $item['status_text'] = PrizeDrawActivity::getStatusText($item['status']);
        unset($item['fake_sale_count'], $item['fake_process']);
        $item['name'] = PrizeDrawActivity::buildTitle($item);
    }
}